#pragma once
#include "net/net_client.h"
#include "parse.h"
#include "regex/myregex.h"
#include "rtp.h"
#include "rtsp_define.h"

#include <arpa/inet.h>
#include <cstdio>
#include <map>
#include <netinet/in.h>
#include <string>

#define DESCRIBE 0
#define SETUP 1

enum ErrorType {
    RTSP_NO_ERROR = 0,
    RTSP_INVALID_URI,
    RTSP_SEND_ERROR,
    RTSP_RECV_ERROR,
    RTSP_PARSE_SDP_ERROR,
    RTSP_INVALID_MEDIA_SESSION,
    RTSP_RESPONSE_BLANK,
    RTSP_RESPONSE_200,
    RTSP_RESPONSE_400,
    RTSP_RESPONSE_401,
    RTSP_RESPONSE_404,
    RTSP_RESPONSE_40X,
    RTSP_RESPONSE_500,
    RTSP_RESPONSE_501,
    RTSP_RESPONSE_50X,
    RTSP_UNKNOWN_ERROR
};

typedef struct _ResponseMsg {
    int         no;
    std::string msg;
} ResponseMsg;

using StreamFunc =
  std::function<void(PayloadType, u_int32_t time_stamp, u_int32_t nalutype, std::vector<u_char>&)>;
class RtspClient {
private:
#ifdef UNITEST
public:
#endif
    /* data */
    std::atomic_bool b_thread_switch_{true};
    u_int32_t        cseq_{0};
    net::Client      client_;

    bool close_flag;

    int         iHeight, iWidth; /* 分辨率 */
    int         iSamplingRate;   //采样率
    std::string vCodeFormat;     //编码格式
    std::string spsDecode, ppsDecode;

    std::string uri_;
    std::string username_;
    std::string password_;
    std::string m_uri_;

    std::string session_;
    std::string interleaved;
    std::string ssrc;
    std::string realm;
    std::string nonce;

    // rtp
    RtpDepay rtpdepay_;
    Parse    parse_;

    // uri
    std::string GetRtspProtoMsg(std::string cmd);
    bool        GetMsgFromUri(std::string uri, std::string& ipstr, int& port, std::string& user,
                              std::string& password);
    ResponseMsg GetResponseMsg(std::string msg);
    std::string MakeMd5DigestResp(std::string cmd, std::string realm, std::string nonce);
    std::string MakeBasicResp();
    ErrorType   CheckAuth(std::string cmd, std::string response);
    void        AnalySDPMessage(std::string uri, std::string msg);
    void        GetSessionID(std::string msg);
    //检查DESCRIBE返回消息的完整性
    bool CheckDESMsgcompleted(const char* msg, int& wantlen);
    //检查DESCRIBE返回消息的是否含有SDP信息
    bool CheckDESMediaMsg(const std::string msg);

    std::thread recv_vdieo_data_th_;
    void        StartRecvVideoData();
    void        RecvVideoDataFunc();
    std::thread keeplive_thd_;

    StreamFunc stream_func_{nullptr};

public:
    RtspClient(/* args */){};
    ~RtspClient() {
        if (recv_vdieo_data_th_.joinable()) {
            recv_vdieo_data_th_.join();
        }
        if (keeplive_thd_.joinable()) {
            recv_vdieo_data_th_.join();
        }
    };

    ErrorType DoDESCRIBE(std::string uri);
    ErrorType DoOPTIONS(std::string uri = "");
    ErrorType DoSETUP();
    ErrorType DoPLAY();
    ErrorType DOTEARDOWN();

    void SendRTCPBye(std::string ssrc_);

    ErrorType PlayUri(std::string uri);

    ErrorType Stop();

    void SetStreamFunc(StreamFunc f) {
        stream_func_ = f;
    }
};
